import numpy as np
from matplotlib import pyplot as plt


from 盒子 import get_adjusted_clusters,get_clusters

 
def drawlines(lines3d_3p):
   
 
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
     # 绘制聚类线条
    for cluster in adjusted_clusters:
        for clusterline in cluster:
            x, y, z = zip(*clusterline)  # 解包元组
            ax.plot(x, y, z, color='blue', linewidth=1)
    line,line2,line3,intersect_line=lines3d_3p
   
    # 绘制主要线条
    x, y, z = zip(*line)  # 解包元组
    ax.plot(x, y, z, color='red', linewidth=3)
    x, y, z = zip(*line2)  # 解包元组
    ax.plot(x, y, z, color='green', linewidth=3)
    x, y, z = zip(*line3)  # 解包元组
    ax.plot(x, y, z, color='yellow', linewidth=3)
    x, y, z = zip(*intersect_line)  # 解包元组
    ax.plot(x, y, z, color='cyan', linewidth=3)
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')
    ax.set_aspect('equal')
    plt.legend()
    plt.show()
def drawlinesproject ( inputline,lines3d_3p1,lines3d_3p2,intersect_line_pre):
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
  
      # 绘制聚类线条
    for cluster in adjusted_clusters:
            for clusterline in cluster:
                x, y, z = zip(*clusterline)  # 解包元组
                ax.plot(x, y, z, color='blue', linewidth=1)
    for line in intersect_line_pre:
        
       
        # 绘制主要线条
        x, y, z = zip(*line)  # 解包元组
        ax.plot(x, y, z, color='cyan', linewidth=3,label="yz")
    for line in lines3d_3p1:
        
       
        # 绘制主要线条
        x, y, z = zip(*line)  # 解包元组
        ax.plot(x, y, z, color='green', linewidth=2,label="yz")
    for line in lines3d_3p2:
        
       
        # 绘制主要线条
        x, y, z = zip(*line)  # 解包元组
        ax.plot(x, y, z, color='yellow', linewidth=2,label="xy")
    x, y, z = zip(*inputline)  # 解包元组
    ax.plot(x, y, z, color='red', linewidth=3)  
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')
    ax.set_aspect('equal')
    plt.legend()
    plt.show()

 
 
def are_within(y1, y2, y3, y4):
    # 确定较小值和较大值
    small = min(y3, y4)
    large = max(y3, y4)
    
    # 检查y1和y2是否都位于small和large之间
    return small <= y1 <= large and small <= y2 <= large
 
 
rel_tol_v=0.1	
def reverse_same(y1, y2, y3, y4):
    return (np.isclose(y3, y1,rtol=rel_tol_v) and\
            np.isclose(y4,y2,rtol=rel_tol_v))or\
               (  np.isclose(y4, y1,rtol=rel_tol_v) and\
            np.isclose(y3,y2,rtol=rel_tol_v))
def merge_collinear_segments(segments, threshold=1e-8):

    """
    合并共线的线段。
    输入：
        segments: 线段列表，每条线段为两个点的元组 ((x1,y1,z1), (x2,y2,z2))
        threshold: 浮点数精度阈值
    输出：
        合并后的线段列表
    """
    def is_collinear(s1, s2):
        A, B = s1
        C, D = s2
        A = np.array(A)
        B = np.array(B)
        C = np.array(C)
        D = np.array(D)
        
        vec_AB = B - A
        vec_CD = D - C
        
        # 检查方向向量是否平行
        cross = np.cross(vec_AB, vec_CD)
        if not np.allclose(cross, 0, atol=threshold):
            return False
        
        # 检查点是否在直线上
        def point_on_line(P, line_start, line_vec):
            vec = P - line_start
            cross = np.cross(vec, line_vec)
            return np.allclose(cross, 0, atol=threshold)
        
        if point_on_line(C, A, vec_AB) or point_on_line(A, C, vec_CD):
            return True
        return False

    # 分组共线线段
    groups = []
    for seg in segments:
        added = False
        for group in groups:
            if is_collinear(seg, group[0]):
                group.append(seg)
                added = True
                break
        if not added:
            groups.append([seg])
    
    merged_segments = []
    for group in groups:
        if not group:
            continue
        
        # 选择参考线段
        ref = group[0]
        A = np.array(ref[0])
        B = np.array(ref[1])
        v = B - A
        
        # 计算所有线段的参数区间
        params = []
        for seg in group:
            p1 = np.array(seg[0])
            p2 = np.array(seg[1])
            t1 = np.dot(p1 - A, v) / np.dot(v, v)
            t2 = np.dot(p2 - A, v) / np.dot(v, v)
            params.append((min(t1, t2), max(t1, t2)))
        
        # 排序并合并区间
        params.sort()
        merged = []
        for p in params:
            if not merged:
                merged.append(p)
            else:
                last = merged[-1]
                if p[0] <= last[1]:
                    merged[-1] = (last[0], max(last[1], p[1]))
                else:
                    merged.append(p)
        
        # 转换为线段
        for t_start, t_end in merged:
            start = A + t_start * v
            end = A + t_end * v
            merged_segments.append((tuple(np.round(start, 8)), tuple(np.round(end, 8))))
    
    # 去重
  
    unique_segments = []
    for seg in merged_segments:
        

        # 检查是否存在一个在偏差范围内的相同线段
        if  not any(all(all(abs(seen_key[i][j] - seg[i][j]) < 0.2 for j in range(3)) for i in range(2)) for seen_key in unique_segments):
            
            unique_segments.append(seg)
    
    return unique_segments

#一开始是计算投影点，后来发现，连起来还得知道点是哪里来的，总不能两个无关的点乱连吧
def get_intersect_lines(xz左右面线段集,yz中间面线段集,xy上下面线段集):
#至于原始线是怎么找的，就是投影线上的两个点去匹配另外两个面上的线，有一个面上的线的两个点要对应坐标相等，另一个面要至少一个点对应坐标相等
    intersect_lines=[[],[],[]]
        
    print(f"xy上下面线段集:{len(xy上下面线段集 )}条线")
    print(f"xz左右面线段集:{len(xz左右面线段集 )}条线")
    print(f"yz中间面线段集:{len(yz中间面线段集 )}条线")
  
    def append_interline(i,intersect_line):
     if intersect_line not in intersect_lines[i] and (intersect_line[1],intersect_line[0])not in intersect_lines[i]:
                        intersect_lines[i].append(intersect_line)
    for line in xz左右面线段集:
        p1,p2=line
        x1,_,z1=p1
        x2,_,z2=p2
        yz=[]
        for line2 in yz中间面线段集:
            p3,p4=line2
            _,y3,z3=p3 
            _,y4,z4=p4
            if (np.isclose(z1,z2,rtol=rel_tol_v)and reverse_same(z1,z2,z3,z4))or\
                (not np.isclose(z1,z2)and are_within(z1,z2,z3,z4)):
             yz.append(((p4,y4),(p3,y3)))
        
    
        xy=[]
        for line3 in xy上下面线段集:
            p5,p6=  line3
            x5,y5,_=p5
            x6,y6,_=p6
            if (np.isclose(x1,x2,rtol=rel_tol_v)and reverse_same(x1,x2,x5,x6))or\
                (not np.isclose(x1,x2,rtol=rel_tol_v)and are_within(x1,x2,x5,x6)):
               xy.append(((p6,y6),(p5,y5)))
       #print("len(yz),len(xy)数目：",len(yz),len(xy))
        intersect_line_pre=[]
        for (p3,y3),(p4,y4) in yz:
            for (p5,y5),(p6,y6) in xy:
            
                yz同y= np.isclose(y3,y4,rtol=rel_tol_v)and\
                    (np.isclose(y3,y5,rtol=rel_tol_v)or np.isclose(y3,y6,rtol=rel_tol_v))
                xy同y= np.isclose(y5,y6,rtol=rel_tol_v)and\
                (np.isclose(y4,y5,rtol=rel_tol_v)or np.isclose(y3,y5,rtol=rel_tol_v))
                投影线对应同y= (np.isclose(y3,y5,rtol=rel_tol_v) and \
                    np.isclose(y4,y6,rtol=rel_tol_v))or (np.isclose(y3,y6,rtol=rel_tol_v) and \
                    np.isclose(y4,y5,rtol=rel_tol_v))
                
                if yz同y or 投影线对应同y  :
                    #print(f"yz同y:{yz同y},xy同y:{xy同y},投影线对应同y:{投影线对应同y}")
                    # print(f"y3:{y3},y4:{y4},y5:{y5},y6:{y6}")
                    
                    intersect_line=((x1,y3,z1),(x2,y4,z2))
                    append_interline(0,intersect_line)
                    intersect_line_pre.append(intersect_line)
                if  xy同y or 投影线对应同y : 
        
                    intersect_line=((x1,y5,z1),(x2,y6,z2))
                    append_interline(0,intersect_line)
                    intersect_line_pre.append(intersect_line)
                    
       
        #print("------------------------")    
        #drawlinesproject(line ,[(p1,p2) for ((p1,_),(p2,_)) in yz],[(p1,p2) for ((p1,_),(p2,_)) in xy],intersect_line_pre)
    
    for line  in xy上下面线段集:
        p1,p2=line
        x1, y1,_ = p1
        x2, y2,_ = p2
        yz = []
        for line2 in yz中间面线段集:
            p3,p4=line2
            _,y3,z3=p3
            _,y4, z4 = p4
            if ( np.isclose(y1,y2,rtol=rel_tol_v) and reverse_same(y1,y2,y3,y4))\
                or( not  np.isclose(y1,y2,rtol=rel_tol_v)and are_within(y1,y2,y3,y4)):
    
                yz.append(((p4,z4),(p3, z3)))
        xz = []
        for line3 in xz左右面线段集:
            p5,p6=  line3
            x5,_, z5 = p5
            x6,_,z6=p6
            if (np.isclose(x1,x2,rtol=rel_tol_v)and  reverse_same(x1,x2,x5,x6))\
                or( not  np.isclose(x1,x2,rtol=rel_tol_v)and are_within(x1,x2,x5,x6) ):
                xz.append(((p6, z6),(p5,z5)))   
       
        for (p3,z3),(p4,z4) in yz:
            for (p5,z5),(p6,z6) in xz:
             yz同z= np.isclose(z3,z4,rtol=rel_tol_v)and\
                (np.isclose(z3,z5,rtol=rel_tol_v)or np.isclose(z3,z6,rtol=rel_tol_v))
             xz同z= np.isclose(z5,z6,rtol=rel_tol_v)and\
            (np.isclose(z4,z5,rtol=rel_tol_v)or np.isclose(z3,z5,rtol=rel_tol_v))
             投影线对应同z=( np.isclose(z3,z5,rtol=rel_tol_v) and \
                np.isclose(z4,z6,rtol=rel_tol_v))or( np.isclose(z3,z6,rtol=rel_tol_v) and \
                np.isclose(z4,z5,rtol=rel_tol_v))
    
             if yz同z or    投影线对应同z :
                    intersect_line = ((x1, y1, z3),(x2,y2,z4))
                    append_interline(1,intersect_line)
             if xz同z or  投影线对应同z:
                    intersect_line=((x1, y1, z5),(x2,y2,z6))
                    append_interline(1,intersect_line)
       
    # drawlinesproject(line ,[(p1,p2) for ((p1,_),(p2,_)) in xy],[(p1,p2) for ((p1,_),(p2,_)) in xz],intersect_line_pre)
    for line in yz中间面线段集:
        p1,p2=line
        _,y1, z1 = p1
        _,y2,z2=p2
        xy = []
        for line2 in xy上下面线段集:
            p3,p4=line2
            x3,y3,_=p3
            x4,y4,_=p4
            if   (np.isclose(y1,y2,rtol=rel_tol_v)and reverse_same(y1,y2,y3,y4))or\
            (not np.isclose(y1,y2,rtol=rel_tol_v)and are_within(y1,y2,y3,y4)): 
                xy.append(((p4,x4),(p3, x3)))
        xz = []
        for line3 in xz左右面线段集:
            p5,p6=line3
            x5,_, z5 = p5
            x6,_,z6=p6
            if  (np.isclose(z1,z2,rtol=rel_tol_v)and reverse_same(z1,z2,z5,z6))or\
                (not np.isclose(z1,z2,rtol=rel_tol_v)and are_within(z1,z2,z5,z6)) :
                xz.append(((p6, x6),(p5,x5)))
       
        for (p3, x3),(p4,x4) in xy:
            for (p5, x5),(p6,x6) in xz:
             xy同x= np.isclose(x3,x4,rtol=rel_tol_v)and\
                (np.isclose(x3,x5,rtol=rel_tol_v)or np.isclose(x3,x6,rtol=rel_tol_v))
             xz同x= np.isclose(x5,x6,rtol=rel_tol_v)and\
            (np.isclose(x4,x5,rtol=rel_tol_v)or np.isclose(x3,x5,rtol=rel_tol_v))
             投影线对应同x= (np.isclose(x3,x5,rtol=rel_tol_v) and \
                np.isclose(x4,x6,rtol=rel_tol_v))or\
            (np.isclose(x3,x6,rtol=rel_tol_v) and \
                np.isclose(x4,x5,rtol=rel_tol_v))
    
             if xy同x or  投影线对应同x :
                    intersect_line = ((x3, y1, z1),(x4,y2,z2)) 
                    append_interline(2,intersect_line)
             if  xz同x or  投影线对应同x:
                    intersect_line = ((x5, y1, z1),(x6,y2,z2)) 
                    append_interline(2,intersect_line)
     
        #drawlinesproject(line ,[(p1,p2) for ((p1,_),(p2,_)) in xy],[(p1,p2) for ((p1,_),(p2,_)) in xz],intersect_line_pre)
    print(f"收集相关线段结束1:{len(intersect_lines[0])+len(intersect_lines[1])+len(intersect_lines[2])}")
    
    
    intersect_lines[0]= list(dict.fromkeys(intersect_lines[0]))
    intersect_lines[1]= list(dict.fromkeys(intersect_lines[1]))
    intersect_lines[2]= list(dict.fromkeys(intersect_lines[2]))

    for i in range(0,3):
    
     intersect_lines[i] = merge_collinear_segments(intersect_lines[i])

    # 定义一个函数来消除坐标差异
    def align_coordinates(lines, step):
        aligned_lines = []
        for line in lines:
            # 四舍五入坐标到最近的step的倍数
            aligned_line = (
                (np.round(line[0][0] / step) * step, np.round(line[0][1] / step) * step, np.round(line[0][2] / step) * step),
                (np.round(line[1][0] / step) * step, np.round(line[1][1] / step) * step, np.round(line[1][2] / step) * step),
                
            )
            aligned_lines.append(aligned_line)
        return aligned_lines

    # 使用函数消除坐标差异，这里以0.2为步长
    intersect_lines1 = align_coordinates(intersect_lines[0], 0.2)
    intersect_lines2 = align_coordinates(intersect_lines[1], 0.2)
    intersect_lines3 = align_coordinates(intersect_lines[2], 0.2)    
    print(f"收集相关线段结束:{len(intersect_lines[0])+len(intersect_lines[1])+len(intersect_lines[2])}")
    return  intersect_lines
if __name__ == "__main__":
    dxf_file_path = 'f.dxf'

    clusters = get_clusters(dxf_file_path)
    adjusted_clusters, yz中间面线段集, xy上下面线段集, xz左右面线段集 = get_adjusted_clusters(clusters)
    intersect_lines = get_intersect_lines(xz左右面线段集, yz中间面线段集, xy上下面线段集)
    intersect_lines1, intersect_lines2, intersect_lines3 = intersect_lines

    fig = plt.figure(figsize=(15, 5))
    axes = []
    for i in range(3):
        ax = fig.add_subplot(1, 3, i+1, projection='3d')
        axes.append(ax)

    # 红色
    for line in intersect_lines1:
        x, y, z = zip(*line)
        axes[0].plot(x, y, z, color="red")
    axes[0].set_title("intersect_lines1")
    axes[0].set_xlabel('X')
    axes[0].set_ylabel('Y')
    axes[0].set_zlabel('Z')
    axes[0].set_aspect('equal')

    # 绿色
    for line in intersect_lines2:
        x, y, z = zip(*line)
        axes[1].plot(x, y, z, color="green")
    axes[1].set_title("intersect_lines2")
    axes[1].set_xlabel('X')
    axes[1].set_ylabel('Y')
    axes[1].set_zlabel('Z')
    axes[1].set_aspect('equal')

    # 黄色
    for line in intersect_lines3:
        x, y, z = zip(*line)
        axes[2].plot(x, y, z, color="yellow")
    axes[2].set_title("intersect_lines3")
    axes[2].set_xlabel('X')
    axes[2].set_ylabel('Y')
    axes[2].set_zlabel('Z')
    axes[2].set_aspect('equal')

    plt.tight_layout()
    plt.show()
